Add a configure script
authorAlex Crichton <alex@alexcrichton.com>
Mon, 28 Jul 2014 15:01:54 +0000 (08:01 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 29 Jul 2014 01:07:09 +0000 (18:07 -0700)
This configure script is similar to rust's in that it doesn't require anything
like autotools, it's just a meta-script to "generate" a makefile and perform
run-of-the-mill validation/discovery before the Makefile is run.

The main purpose of this rewrite is to support multi-target and targeted builds.
This will allow us to produce 32-bit snapshots for platforms as well as easily
providing `./configure --target $foo` for initialization.

cc #274

.gitignore
Makefile [deleted file]
Makefile.in [new file with mode: 0644]
configure [new file with mode: 0755]
src/bin/cargo-version.rs
src/snapshots.txt

index cd8e4b1f6f9ff40692b1a6b7c290a757767c0fa9..48164142ec20b7f0476f8572a310969f2af744af 100644 (file)
@@ -1,2 +1,5 @@
-target
+/target
 .cargo
+/config.stamp
+/Makefile
+/config.mk
diff --git a/Makefile b/Makefile
deleted file mode 100644 (file)
index e89e044..0000000
--- a/Makefile
+++ /dev/null
@@ -1,106 +0,0 @@
-DESTDIR ?=
-PREFIX ?= /usr/local
-PKG_NAME ?= cargo-nightly
-
-ifeq ($(wildcard rustc/bin),)
-export RUSTC := rustc
-else
-export RUSTC := $(CURDIR)/rustc/bin/rustc
-export LD_LIBRARY_PATH := $(CURDIR)/rustc/lib:$(LD_LIBRARY_PATH)
-export DYLD_LIBRARY_PATH := $(CURDIR)/rustc/lib:$(DYLD_LIBRARY_PATH)
-endif
-
-CFG_RELEASE=0.1.0-pre
-CFG_VER_DATE = $(shell git log -1 --pretty=format:'%ai')
-CFG_VER_HASH = $(shell git rev-parse --short HEAD)
-CFG_VERSION = $(PKG_NAME) $(CFG_RELEASE) ($(CFG_VER_HASH) $(CFG_VER_DATE))
-
-export CFG_RELEASE
-export CFG_VER_DATE
-export CFG_VER_HASH
-export CFG_VERSION
-
-export PATH := $(CURDIR)/rustc/bin:$(PATH)
-
-ifeq ($(OS),Windows_NT)
-X = .exe
-endif
-
-TARGET = target
-DISTDIR = $(TARGET)/dist
-PKGDIR = $(DISTDIR)/$(PKG_NAME)
-
-BIN_TARGETS := $(wildcard src/bin/*.rs)
-BIN_TARGETS := $(BIN_TARGETS:src/bin/%.rs=%)
-BIN_TARGETS := $(filter-out cargo,$(BIN_TARGETS))
-BIN_TARGETS := $(BIN_TARGETS:%=$(TARGET)/%$(X))
-
-CARGO := $(TARGET)/snapshot/cargo-nightly/bin/cargo$(X)
-
-all: $(CARGO)
-       $(CARGO) build $(ARGS)
-
-$(CARGO): src/snapshots.txt
-       python src/etc/dl-snapshot.py
-       touch $@
-
-
-# === Tests
-
-test: test-unit style no-exes
-
-test-unit: $(CARGO)
-       $(CARGO) test $(only)
-
-style:
-       sh tests/check-style.sh
-
-no-exes:
-       find $$(git ls-files) -perm +111 -type f \
-               -not -name '*.sh' -not -name '*.rs' | grep '.*' \
-               && exit 1 || exit 0
-
-# === Misc
-
-clean-all: clean
-clean:
-       rm -rf $(TARGET)
-
-dist: $(DISTDIR)/$(PKG_NAME).tar.gz
-
-distcheck: dist
-       rm -rf $(TARGET)/distcheck
-       mkdir -p $(TARGET)/distcheck
-       (cd $(TARGET)/distcheck && tar xf ../dist/$(PKG_NAME).tar.gz)
-       $(TARGET)/distcheck/$(PKG_NAME)/install.sh \
-               --prefix=$(TARGET)/distcheck/install
-       $(TARGET)/distcheck/install/bin/cargo -h > /dev/null
-       $(TARGET)/distcheck/$(PKG_NAME)/install.sh \
-               --prefix=$(TARGET)/distcheck/install --uninstall
-       [ -f $(TARGET)/distcheck/install/bin/cargo ] && exit 1 || exit 0
-
-$(DISTDIR)/$(PKG_NAME).tar.gz: $(PKGDIR)/lib/cargo/manifest.in
-       tar -czvf $@ -C $(DISTDIR) $(PKG_NAME)
-
-$(PKGDIR)/lib/cargo/manifest.in: all
-       rm -rf $(PKGDIR)
-       mkdir -p $(PKGDIR)/bin $(PKGDIR)/lib/cargo
-       cp $(TARGET)/cargo$(X) $(PKGDIR)/bin
-       cp $(BIN_TARGETS) $(PKGDIR)/lib/cargo
-       (cd $(PKGDIR) && find . -type f | sed 's/^\.\///') \
-               > $(DISTDIR)/manifest-$(PKG_NAME).in
-       cp src/etc/install.sh $(PKGDIR)
-       cp README.md LICENSE-MIT LICENSE-APACHE $(PKGDIR)
-       cp LICENSE-MIT $(PKGDIR)
-       mv $(DISTDIR)/manifest-$(PKG_NAME).in $(PKGDIR)/lib/cargo/manifest.in
-
-install: $(PKGDIR)/lib/cargo/manifest.in
-       $(PKGDIR)/install.sh --prefix=$(PREFIX) --destdir=$(DESTDIR)
-
-# Setup phony tasks
-.PHONY: all clean test test-unit style
-
-# Disable unnecessary built-in rules
-.SUFFIXES:
-
-
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..dfb599d
--- /dev/null
@@ -0,0 +1,136 @@
+CFG_RELEASE_NUM=0.0.1
+CFG_RELEASE_LABEL=-pre
+
+include config.mk
+
+ifneq ($(CFG_LOCAL_RUST_ROOT),)
+export LD_LIBRARY_PATH := $(CFG_LOCAL_RUST_ROOT)/lib:$(LD_LIBRARY_PATH)
+export DYLD_LIBRARY_PATH := $(CFG_LOCAL_RUST_ROOT)/lib:$(DYLD_LIBRARY_PATH)
+endif
+
+export PATH := $(dir $(CFG_RUSTC)):$(PATH)
+
+ifdef CFG_ENABLE_NIGHTLY
+CFG_RELEASE=$(CFG_RELEASE_NUM)$(CFG_RELEASE_LABEL)-nightly
+CFG_PACKAGE_VERS = nightly
+else
+CFG_RELEASE=$(CFG_RELEASE_NUM)$(CFG_RELEASE_LABEL)
+CFG_PACKAGE_VERS=$(CFG_RELEASE)
+endif
+CFG_VER_DATE = $(shell git log -1 --pretty=format:'%ai')
+CFG_VER_HASH = $(shell git rev-parse --short HEAD)
+CFG_VERSION = $(CFG_RELEASE) ($(CFG_VER_HASH) $(CFG_VER_DATE))
+PKG_NAME = cargo-$(CFG_PACKAGE_VERS)
+
+ifdef CFG_DISABLE_VERIFY_INSTALL
+MAYBE_DISABLE_VERIFY=--disable-verify
+else
+MAYBE_DISABLE_VERIFY=
+endif
+
+export CFG_VERSION
+
+ifeq ($(OS),Windows_NT)
+X = .exe
+endif
+
+TARGET_ROOT = target
+BIN_TARGETS := $(wildcard src/bin/*.rs)
+BIN_TARGETS := $(BIN_TARGETS:src/bin/%.rs=%)
+BIN_TARGETS := $(filter-out cargo,$(BIN_TARGETS))
+
+define DIST_TARGET
+TARGET_$(1) = $$(TARGET_ROOT)/$(1)
+DISTDIR_$(1) = $$(TARGET_$(1))/dist
+PKGDIR_$(1) = $$(DISTDIR_$(1))/$$(PKG_NAME)-$(1)
+BIN_TARGETS_$(1) := $$(BIN_TARGETS:%=$$(TARGET_$(1))/%$$(X))
+endef
+$(foreach target,$(CFG_TARGET),$(eval $(call DIST_TARGET,$(target))))
+
+CARGO := $(TARGET_ROOT)/snapshot/cargo-nightly/bin/cargo$(X)
+
+all: $(foreach target,$(CFG_TARGET),cargo-$(target))
+
+define CARGO_TARGET
+cargo-$(1): $$(CARGO)
+       $$(CARGO) build --target $(1) $$(ARGS)
+endef
+$(foreach target,$(CFG_TARGET),$(eval $(call CARGO_TARGET,$(target))))
+
+$(CARGO): src/snapshots.txt
+       $(CFG_PYTHON) src/etc/dl-snapshot.py
+       touch $@
+
+
+# === Tests
+
+test: test-unit style no-exes
+
+test-unit: $(CARGO)
+       $(CARGO) test $(only)
+
+style:
+       sh tests/check-style.sh
+
+no-exes:
+       find $$(git ls-files) -perm +111 -type f \
+               -not -name configure -not -name '*.sh' -not -name '*.rs' | \
+               grep '.*' \
+               && exit 1 || exit 0
+
+# === Misc
+
+clean-all: clean
+clean:
+       rm -rf $(TARGET_ROOT)
+
+# === Distribution
+
+define DO_DIST_TARGET
+dist-$(1): $$(DISTDIR_$(1))/$$(PKG_NAME)-$(1).tar.gz
+
+distcheck-$(1): dist-$(1)
+       rm -rf $$(TARGET_$(1))/distcheck
+       mkdir -p $$(TARGET_$(1))/distcheck
+       (cd $$(TARGET_$(1))/distcheck && tar xf ../dist/$$(PKG_NAME)-$(1).tar.gz)
+       $$(TARGET_$(1))/distcheck/$$(PKG_NAME)-$(1)/install.sh \
+               --prefix=$$(TARGET_$(1))/distcheck/install
+       $$(TARGET_$(1))/distcheck/install/bin/cargo -V > /dev/null
+       $$(TARGET_$(1))/distcheck/$$(PKG_NAME)-$(1)/install.sh \
+               --prefix=$$(TARGET_$(1))/distcheck/install --uninstall
+       [ -f $$(TARGET_$(1))/distcheck/install/bin/cargo ] && exit 1 || exit 0
+
+$$(DISTDIR_$(1))/$$(PKG_NAME)-$(1).tar.gz: $$(PKGDIR_$(1))/lib/cargo/manifest.in
+       tar -czvf $$@ -C $$(@D) $$(PKG_NAME)-$(1)
+
+$$(PKGDIR_$(1))/lib/cargo/manifest.in: all
+       rm -rf $$(PKGDIR_$(1))
+       mkdir -p $$(PKGDIR_$(1))/bin $$(PKGDIR_$(1))/lib/cargo
+       cp $$(TARGET_$(1))/cargo$$(X) $$(PKGDIR_$(1))/bin
+       cp $$(BIN_TARGETS_$(1)) $$(PKGDIR_$(1))/lib/cargo
+       (cd $$(PKGDIR_$(1)) && find . -type f | sed 's/^\.\///') \
+               > $$(DISTDIR_$(1))/manifest-$$(PKG_NAME).in
+       cp src/etc/install.sh $$(PKGDIR_$(1))
+       cp README.md LICENSE-MIT LICENSE-APACHE $$(PKGDIR_$(1))
+       cp LICENSE-MIT $$(PKGDIR_$(1))
+       mv $$(DISTDIR_$(1))/manifest-$$(PKG_NAME).in \
+               $$(PKGDIR_$(1))/lib/cargo/manifest.in
+
+install-$(1): $$(PKGDIR_$(1))/lib/cargo/manifest.in
+       $$(PKGDIR_$(1))/install.sh \
+               --prefix="$$(DESTDIR)$$(CFG_PREFIX)" \
+               --destdir="$$(DESTDIR)" $$(MAYBE_DISABLE_VERIFY)
+endef
+$(foreach target,$(CFG_TARGET),$(eval $(call DO_DIST_TARGET,$(target))))
+
+dist: $(CARGO) $(foreach target,$(CFG_TARGET),dist-$(target))
+distcheck: $(CARGO) $(foreach target,$(CFG_TARGET),distcheck-$(target))
+install: $(CARGO) $(foreach target,$(CFG_TARGET),install-$(target))
+
+# Setup phony tasks
+.PHONY: all clean test test-unit style
+
+# Disable unnecessary built-in rules
+.SUFFIXES:
+
+
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..c6b9cf5
--- /dev/null
+++ b/configure
@@ -0,0 +1,379 @@
+#!/bin/sh
+
+msg() {
+    echo "configure: $1"
+}
+
+step_msg() {
+    msg
+    msg "$1"
+    msg
+}
+
+warn() {
+    echo "configure: WARNING: $1"
+}
+
+err() {
+    echo "configure: error: $1"
+    exit 1
+}
+
+need_ok() {
+    if [ $? -ne 0 ]
+    then
+        err "$1"
+    fi
+}
+
+need_cmd() {
+    if command -v $1 >/dev/null 2>&1
+    then msg "found $1"
+    else err "need $1"
+    fi
+}
+
+make_dir() {
+    if [ ! -d $1 ]
+    then
+        msg "mkdir -p $1"
+        mkdir -p $1
+    fi
+}
+
+copy_if_changed() {
+    if cmp -s $1 $2
+    then
+        msg "leaving $2 unchanged"
+    else
+        msg "cp $1 $2"
+        cp -f $1 $2
+        chmod u-w $2 # make copied artifact read-only
+    fi
+}
+
+move_if_changed() {
+    if cmp -s $1 $2
+    then
+        msg "leaving $2 unchanged"
+    else
+        msg "mv $1 $2"
+        mv -f $1 $2
+        chmod u-w $2 # make moved artifact read-only
+    fi
+}
+
+putvar() {
+    local T
+    eval T=\$$1
+    eval TLEN=\${#$1}
+    if [ $TLEN -gt 35 ]
+    then
+        printf "configure: %-20s := %.35s ...\n" $1 "$T"
+    else
+        printf "configure: %-20s := %s %s\n" $1 "$T" "$2"
+    fi
+    printf "%-20s := %s\n" $1 "$T" >>config.tmp
+}
+
+probe() {
+    local V=$1
+    shift
+    local P
+    local T
+    for P
+    do
+        T=$(command -v $P 2>&1)
+        if [ $? -eq 0 ]
+        then
+            VER0=$($P --version 2>/dev/null | head -1 \
+                |  sed -e 's/[^0-9]*\([vV]\?[0-9.]\+[^ ]*\).*/\1/' )
+            if [ $? -eq 0 -a "x${VER0}" != "x" ]
+            then
+              VER="($VER0)"
+            else
+              VER=""
+            fi
+            break
+        else
+            VER=""
+            T=""
+        fi
+    done
+    eval $V=\$T
+    putvar $V "$VER"
+}
+
+probe_need() {
+    local V=$1
+    probe $*
+    eval VV=\$$V
+    if [ -z "$VV" ]
+    then
+        err "needed, but unable to find any of: $*"
+    fi
+}
+
+validate_opt () {
+    for arg in $CFG_CONFIGURE_ARGS
+    do
+        isArgValid=0
+        for option in $BOOL_OPTIONS
+        do
+            if test --disable-$option = $arg
+            then
+                isArgValid=1
+            fi
+            if test --enable-$option = $arg
+            then
+                isArgValid=1
+            fi
+        done
+        for option in $VAL_OPTIONS
+        do
+            if echo "$arg" | grep -q -- "--$option="
+            then
+                isArgValid=1
+            fi
+        done
+        if [ "$arg" = "--help" ]
+        then
+            echo
+            echo "No more help available for Configure options,"
+            echo "check the Wiki or join our IRC channel"
+            break
+        else
+            if test $isArgValid -eq 0
+            then
+                err "Option '$arg' is not recognized"
+            fi
+        fi
+    done
+}
+
+valopt() {
+    VAL_OPTIONS="$VAL_OPTIONS $1"
+
+    local OP=$1
+    local DEFAULT=$2
+    shift
+    shift
+    local DOC="$*"
+    if [ $HELP -eq 0 ]
+    then
+        local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_')
+        local V="CFG_${UOP}"
+        eval $V="$DEFAULT"
+        for arg in $CFG_CONFIGURE_ARGS
+        do
+            if echo "$arg" | grep -q -- "--$OP="
+            then
+                val=$(echo "$arg" | cut -f2 -d=)
+                eval $V=$val
+            fi
+        done
+        putvar $V
+    else
+        if [ -z "$DEFAULT" ]
+        then
+            DEFAULT="<none>"
+        fi
+        OP="${OP}=[${DEFAULT}]"
+        printf "    --%-30s %s\n" "$OP" "$DOC"
+    fi
+}
+
+opt() {
+    BOOL_OPTIONS="$BOOL_OPTIONS $1"
+
+    local OP=$1
+    local DEFAULT=$2
+    shift
+    shift
+    local DOC="$*"
+    local FLAG=""
+
+    if [ $DEFAULT -eq 0 ]
+    then
+        FLAG="enable"
+    else
+        FLAG="disable"
+        DOC="don't $DOC"
+    fi
+
+    if [ $HELP -eq 0 ]
+    then
+        for arg in $CFG_CONFIGURE_ARGS
+        do
+            if [ "$arg" = "--${FLAG}-${OP}" ]
+            then
+                OP=$(echo $OP | tr 'a-z-' 'A-Z_')
+                FLAG=$(echo $FLAG | tr 'a-z' 'A-Z')
+                local V="CFG_${FLAG}_${OP}"
+                eval $V=1
+                putvar $V
+            fi
+        done
+    else
+        if [ ! -z "$META" ]
+        then
+            OP="$OP=<$META>"
+        fi
+        printf "    --%-30s %s\n" "$FLAG-$OP" "$DOC"
+     fi
+}
+
+envopt() {
+    local NAME=$1
+    local V="CFG_${NAME}"
+    eval VV=\$$V
+
+    # If configure didn't set a value already, then check environment.
+    #
+    # (It is recommended that the configure script always check the
+    # environment before setting any values to envopt variables; see
+    # e.g.  how CFG_CC is handled, where it first checks `-z "$CC"`,
+    # and issues msg if it ends up employing that provided value.)
+    if [ -z "$VV" ]
+    then
+        eval $V=\$$NAME
+        eval VV=\$$V
+    fi
+
+    # If script or environment provided a value, save it.
+    if [ ! -z "$VV" ]
+    then
+        putvar $V
+    fi
+}
+
+msg "looking for configure programs"
+need_cmd cmp
+need_cmd mkdir
+need_cmd printf
+need_cmd cut
+need_cmd head
+need_cmd grep
+need_cmd xargs
+need_cmd cp
+need_cmd find
+need_cmd uname
+need_cmd date
+need_cmd tr
+need_cmd sed
+need_cmd file
+
+CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
+CFG_BUILD_DIR="$(pwd)/"
+CFG_SELF="$0"
+CFG_CONFIGURE_ARGS="$@"
+
+OPTIONS=""
+HELP=0
+if [ "$1" = "--help" ]
+then
+    HELP=1
+    shift
+    echo
+    echo "Usage: $CFG_SELF [options]"
+    echo
+    echo "Options:"
+    echo
+else
+    msg "recreating config.tmp"
+    echo '' >config.tmp
+
+    step_msg "processing $CFG_SELF args"
+fi
+
+BOOL_OPTIONS=""
+VAL_OPTIONS=""
+
+opt debug 1 "build with extra debug fun"
+opt nightly 0 "build nightly packages"
+opt verify-install 1 "verify installed binaries work"
+valopt prefix "/usr/local" "set installation prefix"
+valopt local-rust-root "" "set prefix for local rust binary"
+
+if [ $HELP -eq 0 ]; then
+    if [ ! -z "${CFG_LOCAL_RUST_ROOT}" ]; then
+        export LD_LIBRARY_PATH="${CFG_LOCAL_RUST_ROOT}/lib:$LD_LIBRARY_PATH"
+        export DYLD_LIBRARY_PATH="${CFG_LOCAL_RUST_ROOT}/lib:$DYLD_LIBRARY_PATH"
+        LRV=`${CFG_LOCAL_RUST_ROOT}/bin/rustc --version`
+        if [ $? -eq 0 ]; then
+            step_msg "using rustc at: ${CFG_LOCAL_RUST_ROOT} with version: $LRV"
+        else
+            err "failed to run rustc at: ${CFG_LOCAL_RUST_ROOT}"
+        fi
+        CFG_RUSTC="${CFG_LOCAL_RUST_ROOT}/bin/rustc"
+    else
+        probe_need CFG_RUSTC        rustc
+    fi
+    DEFAULT_BUILD=$(${CFG_RUSTC} --version verbose | grep 'host: ' | sed 's/host: //')
+fi
+
+valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
+valopt host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples"
+valopt target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
+
+valopt localstatedir "/var/lib" "local state directory"
+valopt sysconfdir "/etc" "install system configuration files"
+valopt datadir "${CFG_PREFIX}/share" "install data"
+valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
+valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
+valopt libdir "${CFG_PREFIX}/lib" "install libraries"
+
+if [ $HELP -eq 1 ]
+then
+    echo
+    exit 0
+fi
+
+# Validate Options
+step_msg "validating $CFG_SELF args"
+validate_opt
+
+step_msg "looking for build programs"
+
+probe_need CFG_CURLORWGET  curl wget
+probe_need CFG_PYTHON      python
+
+# a little post-processing of various config values
+CFG_PREFIX=${CFG_PREFIX%/}
+CFG_MANDIR=${CFG_MANDIR%/}
+CFG_HOST="$(echo $CFG_HOST | tr ',' ' ')"
+CFG_TARGET="$(echo $CFG_TARGET | tr ',' ' ')"
+
+# copy host-triples to target-triples so that hosts are a subset of targets
+V_TEMP=""
+for i in $CFG_HOST $CFG_TARGET;
+do
+   echo "$V_TEMP" | grep -qF $i || V_TEMP="$V_TEMP${V_TEMP:+ }$i"
+done
+CFG_TARGET=$V_TEMP
+
+if [ "$CFG_SRC_DIR" != "$CFG_BUILD_DIR" ]; then
+    err "cargo does not currently support an out-of-tree build dir"
+fi
+
+step_msg "writing configuration"
+
+putvar CFG_SRC_DIR
+putvar CFG_BUILD_DIR
+putvar CFG_CONFIGURE_ARGS
+putvar CFG_PREFIX
+putvar CFG_BUILD
+putvar CFG_HOST
+putvar CFG_TARGET
+putvar CFG_LIBDIR
+putvar CFG_MANDIR
+putvar CFG_RUSTC
+
+msg
+copy_if_changed ${CFG_SRC_DIR}Makefile.in ./Makefile
+move_if_changed config.tmp config.mk
+rm -f config.tmp
+touch config.stamp
+
+step_msg "complete"
+msg
index 3f0b2e0de07733964519a088a893dd1466a87274..4c5b1e0d22eb114b87f4784c0cc930e2b14968db 100644 (file)
@@ -27,7 +27,7 @@ fn main() {
 fn execute(_: Options, _: &mut MultiShell) -> CliResult<Option<()>> {
     debug!("executing; cmd=cargo-version; args={}", os::args());
 
-    println!("{}", env!("CFG_VERSION"));
+    println!("cargo {}", env!("CFG_VERSION"));
 
     Ok(None)
 }
index 3b0618d14e6df06ccfbded6f73f45228d2356282..7869ab79149750dd06b2c14cc6068681a0771dd2 100644 (file)
@@ -1,3 +1,8 @@
+2014-07-29
+  mac 53f8bc39132e987d25e022698c3234fee0916ecf
+  linux b7dbdc89126577fda2eef7d63c5f7fc1d8d28f99
+  win 9551454e2ce649d146ad8d856cee3672ab0def02
+
 2014-07-26
   mac 9a78815c7fcdb1cdabc93eb120f80444f209d968
   linux b38e7c45292d2cc6a1932fa9a1f349f9b92c0c1d